package com.yenroc.ho.runner;

import com.yenroc.ho.common.context.SpringContextHolder;
import com.yenroc.ho.mapper.base.BlogCommonMapper;
import com.yenroc.ho.utils.compiler.JavaStringCompiler;
import com.yenroc.ho.utils.compiler.MemoryClassLoader;
import com.yenroc.ho.utils.dd.DynamicLoader;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.*;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.spring.mapper.MapperFactoryBean;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author： heyanpeng
 * @date： 2021/7/19
 * 参考： https://www.cnblogs.com/yanjie-java/p/7940929.html
 *       https://github.com/michaelliao/compiler
 */
@Component
@Order(value=1)
public class InitMapperRunner extends ClassPathScanningCandidateComponentProvider implements ApplicationRunner{

    private static final Logger log = LoggerFactory.getLogger(InitMapperRunner.class);

    @Autowired
    DefaultListableBeanFactory defaultListableBeanFactory;

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;



    MapperHelper mapperHelper = new MapperHelper();

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("开始初始化动态Mapper接口。。");
        long start = System.currentTimeMillis();
        String[] classNames = new String[]{"BTest1","Ctest1","Ctest2","DTest1","Etest1","Etest2","FTest1","Gtest1","Gtest2","HTest1"};
        List<Class> classList = new ArrayList<>();
        for (int i = 0; i < classNames.length; i++) {
            Class clazz = createClass(classNames[i]);
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
            String beanClassName = definition.getBeanClassName();
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
            definition.getPropertyValues().add("sqlSessionFactory", sqlSessionFactory);
            definition.getPropertyValues().add("sqlSessionTemplate", sqlSessionTemplate);
            definition.getPropertyValues().add("mapperHelper", mapperHelper);
            definition.setBeanClass(MapperFactoryBean.class);
            definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
            defaultListableBeanFactory.registerBeanDefinition(clazz.getSimpleName(), definition);
            BlogCommonMapper dynamicTestDao = SpringContextHolder.getBean(classNames[i]);
            System.out.println(classNames[i] +"=" + dynamicTestDao);
            System.out.println(classNames[i] + "result=" + dynamicTestDao.selectAll());
            classList.add(clazz);
        }
        long end = System.currentTimeMillis();
        System.out.println("加载完成耗时="+(end-start));
    }

    private Class createClass(String className) throws ClassNotFoundException {
        String daoStr = getDaoStr(className);
        Map<String, byte[]> compile = DynamicLoader.compile(className + ".java", daoStr);

        // 写入到class文件
//        try {
//            writeFile(compile);
//        } catch (IOException e) {
//            log.info("生成class文件失败");
//        }

        DynamicLoader.MemoryClassLoader classLoader = DynamicLoader.getMemoryClassLoader();
        return classLoader.loadClass("com.yenroc.ho.mapper.dynamic." + className);
    }

    private static String getDaoStr(String className) {
        return  "package com.yenroc.ho.mapper.dynamic;\n" +
                "\n" +
                "import com.yenroc.ho.mapper.entity.Demo;\n" +
                "import com.yenroc.ho.mapper.base.BlogCommonMapper;\n" +
                "\n" +
                "/**\n" +
                " * @author： heyanpeng\n" +
                " * @date： 2021/7/20\n" +
                " * @desc： 因为手动注册bean,所以不需要Mapper注解 \n" +
                " */\n" +
                "public interface "+className+" extends BlogCommonMapper<Demo> {\n" +
                "}\n";
    }


    private void writeFile(Map<String, byte[]> results) throws IOException {
        Set<String> strings = results.keySet();
        for (String key : strings) {
            FileOutputStream fos = new FileOutputStream(System.getProperty("user.dir")+"/target/classes/" + key.replace(".","/") + ".class");
            byte[] bytes = results.get(key);
            fos.write(bytes,0,bytes.length);
            fos.close();
        }
    }

}
